<?php
/**
 * Created by PhpStorm.
 * User: BlueIdeaLirui
 * Date: 2019/09/04
 * Time: 14:58
 */

namespace business\elasticsearch\services\upgrade;

use business\elasticsearch\caches\LandCache;
use business\elasticsearch\repositories\upgrade\LandProjectRepository;

class LandProjectService
{
    /**
     * 市场数据-项目数据列表
     * @param string $region
     * @param string $startDate
     * @param string $endDate
     * @param string $decorate
     * @param $page
     * @param $pageSize
     * @return array
     */
    public function getList
    (
        $region = '',
        $startDate = '',
        $endDate = '',
        $decorate = '',
        $page,
        $pageSize
    ) {
        $page = max($page, 1);

        $query = [];

        $totalCount = $totalArea = $totalFee = 0;
        $list = [];

        // 构建查询条件
        $this->builderQueryConds($query, $region, $startDate, $endDate, $decorate);

        // 获取数量
        $count = (new LandProjectRepository())->queryCount($query, [
            [
                'name' => 'count',
                'options' => [
                    'cardinality' => [
                        'field' => 'company_name.keyword',
                        'precision_threshold' => 40000
                    ]
                ]
            ]
        ]);

        if (!empty($count)) {
            $from = ($page - 1) * $pageSize;

            $include = [
                'uid'
                , 'developer_uid'
                , 'company_name'
                , 'opening_time'
                , 'decorate'
                , 'area'
                , 'price'
                , 'created_time'
            ];

            list($total, $data) = (new LandProjectRepository())->queryList(
                $query, $include, $this->builerAggs(
                    $page, $pageSize, false));

            $cacheCount = (int)LandCache::getRecordByString(
                'land_project_count' . '_' . md5(serialize($query)));

            $result = ['resultNum' => !empty($cacheCount)
                ? $cacheCount
                : $this->getCountRecord(
                    $query, $include, $count, $page, $pageSize)
                , 'resultSet' => []];

            $totalCount  = $total;
            $totalArea   = $this->getRound($data['totalarea']['value']);
            $totalFee    = $this->getRound($data['totalfee']['value']);

            $bucketsList = array_slice($data['aggregations']['buckets'], $from, $pageSize);
            $list        = $this->filterLandProject($bucketsList);
        }

        $result['resultSet'] = [
            'totalCount' => (int)$totalCount, 'totalArea' => (int)$totalArea, 'totalFee' => (int)$totalFee, 'list' => $list
        ];

        return $result;
    }

    /**
     * 返回四舍五入后的结果值
     * @param int $number
     * @param int $precision
     * @return float|int
     */
    protected function getRound($number = 0, $precision = 2)
    {
        if (is_numeric($number)) {
            return round($number, $precision);
        }
        return 0;
    }

    /**
     * 获取小数点后的数值
     * @param string $number
     * @return int
     */
    protected static function getDecimalPointNumber
    (
        $number = ''
    ) {
        if (!empty($number)) {
            return (int)explode('.', $number)[1];
        }

        return 0;
    }

    /**
     * 返回数量
     * @param $query
     * @param $include
     * @param int $count
     * @param int $page
     * @param int $pageSize
     * @return int
     */
    protected function getCountRecord
    (
        $query,
        $include,
        $count = 0,
        $page = 0,
        $pageSize = 10
    ) {
        list(, $data) = (new LandProjectRepository())->queryList($query, $include, $this->builerAggs($page, $pageSize));
        $buckets = $data['aggregations']['buckets'];
        if (!empty($buckets)) {
            $number = $count / $pageSize;
            $pageCount = ceil($number);
            $lastResult = array_slice($buckets, ($pageCount - 1) * $pageSize, $pageSize);
            $decimalPointNumber = (int)static::getDecimalPointNumber($number);
            if (!empty($decimalPointNumber)) {
                if (empty($lastResult)) {
                    $count -= 1;
                } else {
                    $count = $count - (int)($decimalPointNumber - count($lastResult));
                }
            } else {
                if (!empty($lastResult)) {
                    $count = (int)(($pageCount - 1) . count($lastResult));
                }
            }
            LandCache::saveRecordByString('land_project_count' . '_' . md5(serialize($query)), 0, $count);
            return $count;
        }
        return 0;
    }

    /**
     * 过滤数据
     * @param array $buckets
     * @return array
     */
    protected function filterLandProject($buckets = [])
    {
        if (!empty($buckets)) {
            $data = [];
            $types = ['毛坯', '非毛坯'];
            foreach ($buckets as & $value) {
                $tmp['developer_uid'] = $value['developer_uid']['value'];
                $tmp['company_name']  = $value['key'];
                $tmp['total_count']   = $value['doc_count'];
                $tmp['totalarea']     = $this->getRound($value['totalarea']['value']);

                $decorates = $value['decorate']['buckets'];

                $merges = $newDecorate = [];

                if (!empty($decorates)) {
                    foreach ($decorates as $key => $item) {
                        $type = current(explode(',', $item['key']));
                        if (in_array($type, $types)) {
                            $merges[] = ['key' => $type, 'doc_count' => $item['doc_count']];
                        }
                    }

                    foreach ($types as $v) {
                        $docNum = $this->mergeDecorate($v, $merges);
                        if (!empty($docNum)) {
                            $newDecorate[] = ['key' => $v, 'doc_count' => $docNum];
                        }
                    }
                }

                $value['decorate']['buckets'] = !empty($newDecorate) ? $newDecorate : null;

                $tmp['decorate'] = $value['decorate']['buckets'];
                $data[]          = $tmp;
            }

            return $data;
        }

        return [];
    }

    /**
     * 合并装修状况
     * @param string $name
     * @param array $decorates
     * @return int
     */
    protected function mergeDecorate(
        $name = '',
        $merges = []
    ) {
        $docNum = 0;
        if (!empty($name) && !empty($merges)) {
            if (!empty($merges)) {
                foreach ($merges as $key => $item) {
                    if ($item['key'] == $name) {
                        $docNum += $item['doc_count'];
                    }
                }
            }
        }

        return $docNum;
    }

    /**
     * 构建大数据拓客--项目数据-查询条件
     * @param array $query
     * @param string $region
     * @param string $startDate
     * @param string $endDate
     * @param string $decorate
     */
    protected function builderQueryConds
    (
        &$query = [],
        $region = '',
        $startDate = '',
        $endDate = '',
        $decorate = ''
    ) {
        $bool = [];
        $pointer = 0;

        // 构建时间周期查询
        $this->builerDateQuery($bool, $startDate, $endDate, $pointer);
        // 构建项目地区查询
        $this->builerAreaQuery($bool, $region, $pointer);
        // 构建装修查询
        $this->builerDecorateQuery($bool, $decorate, $pointer);

        !empty($bool) && $query['bool'] = $bool;
    }

    /**
     * 构建大数据拓客--项目数据-开盘时间查询条件
     * @param array $bool
     * @param string $startDate
     * @param string $endDate
     * @param $pointer
     */
    protected function builerDateQuery
    (
        &$bool = [],
        $startDate = '',
        $endDate = '',
        &$pointer
    ) {
        // 构建时间周期查询
        if (!empty($startDate) && !empty($endDate)) {
            $bool['filter']['bool']['must'][$pointer]['bool']['must'][][] = [
                'range' => [
                    'opening_time' => [
                        'gte' => date('Y-m-01', strtotime($startDate)),
                        'lte' => date('Y-m-t', strtotime($endDate))
                    ]
                ]
            ];
            $pointer++;
        }
    }

    /**
     * 构建项目地区查询
     * @param array $bool
     * @param $region
     * @param $pointer
     */
    protected function builerAreaQuery
    (
        &$bool = [],
        $region,
        &$pointer
    ) {
        if (!empty($region)) {
            $region = explode(',', $region);
            foreach ($region as $item) {
                $keys = ['city_code', 'province_code'];
                if (!empty($keys)) {
                    array_walk($keys,
                        function
                        (
                            $value
                        )
                        use (
                            &$bool,
                            &$pointer,
                            $item
                        ) {
                            $bool['filter']['bool']['must'][$pointer]['bool']['should'][] = [
                                'term' => [
                                    $value . '.keyword' => $item
                                ]
                            ];
                        });
                }
            }
            $pointer++;
        }
    }

    /**
     * 构建装修查询
     * @param array $bool
     * @param $decorate
     * @param $pointer
     */
    protected function builerDecorateQuery
    (
        &$bool = [],
        $decorate,
        &$pointer
    ) {
        if (!empty($decorate)
            && $decorate != '全部') {
            $decorates = explode(',', $decorate);
            foreach ($decorates as $decorate) {
                $bool['filter']['bool']['must'][$pointer]['bool']['should'][] = [
                    'match_phrase' => [
                        'decorate.keyword' => $decorate
                    ]
                ];
            }
            $pointer++;
        }
    }

    /**
     * 返回总面积聚合条件
     * @return array
     */
    protected function getTotalAreaAggs()
    {
        return ['name' => 'totalarea', 'options' => ['sum' => ['field' => 'area']]];
    }

    /**
     * 返回总金额聚合条件
     * @return array
     */
    protected function getTotalFeeAggs()
    {
        return ['name' => 'totalfee', 'options' => ['sum' => ['field' => 'total_price']]];
    }

    /**
     * 构建大数据拓客--项目数据-聚合
     * @param $page
     * @param $pageSize
     * @param bool $isTotalQuantity
     * @return array
     */
    protected function builerAggs($page, $pageSize, $isTotalQuantity = true)
    {
        $size = $page * $pageSize;
        return [
            $this->getTotalAreaAggs()
            , $this->getTotalFeeAggs()
            , [
                'name' => 'aggregations',
                'options' => [
                    'terms' => [
                        'field' => 'company_name.keyword',
                        'order' => [
                            'totalarea' => 'desc'
                        ],
                        'size' => $isTotalQuantity ? pow(2,31) - 1 : $size
                    ],
                    'aggregations' => [
                        'developer_uid' => [
                            'max' => [
                                'field' => 'developer_uid'
                            ]
                        ],
                        'totalarea' => [
                            'sum' => [
                                'field' => 'area'
                            ]
                        ],
                        'decorate' => [
                            'terms' => [
                                'field' => 'decorate.keyword',
                                'size' => pow(2,31) - 1
                            ],
                        ]
                    ]
                ]
            ]
        ];
    }
}
